
#include   "tx_api.h"
#include   "nx_api.h"
extern void    test_control_return(UINT status);

#if !defined(NX_DISABLE_IPV4) && defined(NX_DISABLE_UDP_RX_CHECKSUM)
#include   "nxd_dhcp_client.h"
#include   "nxd_dhcp_server.h"

#define     DEMO_STACK_SIZE             4096
#define     NX_PACKET_SIZE              1536
#define     NX_PACKET_POOL_SIZE         NX_PACKET_SIZE * 8
                                                               
#define     NX_DHCP_SERVER_IP_ADDRESS_0 IP_ADDRESS(192, 168, 3, 8)   
#define     START_IP_ADDRESS_LIST_0     IP_ADDRESS(192, 168, 3, 11)
#define     END_IP_ADDRESS_LIST_0       IP_ADDRESS(192, 168, 3,20)

#define     NX_DHCP_SUBNET_MASK_0       IP_ADDRESS(255,255,255,0)
#define     NX_DHCP_DEFAULT_GATEWAY_0   IP_ADDRESS(192, 168, 3, 8)
#define     NX_DHCP_DNS_SERVER_0        IP_ADDRESS(192, 168, 3, 8)

/* Define the ThreadX and NetX object control blocks...  */
static NX_PACKET_POOL          client_pool;

static TX_THREAD               server_thread;
static NX_PACKET_POOL          server_pool;
static NX_IP                   server_ip;
static NX_DHCP_SERVER          dhcp_server;

/* Define the counters used in the demo application...  */

static ULONG                   error_counter;
static ULONG                   resposner_counter;
static CHAR                    *pointer;  

/* Define thread prototypes.  */

static void    server_thread_entry(ULONG thread_input);

/******** Optionally substitute your Ethernet driver here. ***********/
extern void    _nx_ram_network_driver_1024(struct NX_IP_DRIVER_STRUCT *driver_req);  
           


/* Frame (342 bytes)  DHCP DISCOVER Read overflow.  */
static const unsigned char pkt1[342] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, /* .......P */
0xb6, 0x07, 0xa1, 0x69, 0x08, 0x00, 0x45, 0x00, /* ...i..E. */
0x01, 0x48, 0x00, 0x01, 0x00, 0x00, 0x80, 0x11, /* .H...... */
0x39, 0xa5, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* 9....... */
0xff, 0xff, 0x00, 0x44, 0x00, 0x43, 0x01, 0x34, /* ...D.C.4 */
0x83, 0x9e, 0x01, 0x01, 0x06, 0x00, 0x00, 0xf6, /* ........ */
0x16, 0xc2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, /* .......P */
0xb6, 0x07, 0xa1, 0x69, 0x00, 0x00, 0x00, 0x00, /* ...i.... */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, /* ......c. */
0x53, 0x63, 0x37, 0x3c, 0x00, 0x00, 0x00, 0x00, /* Sc5..=.. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* .P...i.. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* CW-9WDPJ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* V1-GA1<. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MSFT 5.0 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 7.....,. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /.!y.+.. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00              /* ...... */
};


/* Frame (342 bytes)  DHCP DISCOVER Write overflow. */
static const unsigned char pkt2[342] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, /* .......P */
0xb6, 0x07, 0xa1, 0x69, 0x08, 0x00, 0x45, 0x00, /* ...i..E. */
0x01, 0x48, 0x00, 0x01, 0x00, 0x00, 0x80, 0x11, /* .H...... */
0x39, 0xa5, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* 9....... */
0xff, 0xff, 0x00, 0x44, 0x00, 0x43, 0x01, 0x34, /* ...D.C.4 */
0x83, 0x9e, 0x01, 0x01, 0x06, 0x00, 0x00, 0xf6, /* ........ */
0x16, 0xc2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, /* .......P */
0xb6, 0x07, 0xa1, 0x69, 0x00, 0x00, 0x00, 0x00, /* ...i.... */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, /* ......c. */
0x53, 0x63, 0x37, 0x14, 0x35, 0x35, 0x35, 0x35, /* Sc5..=.. */
0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, /* .P...i.. */
0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, /* CW-9WDPJ */
0x56, 0x31, 0x2d, 0x47, 0x41, 0x31, 0x3c, 0x08, /* V1-GA1<. */
0x4d, 0x53, 0x46, 0x54, 0x20, 0x35, 0x2e, 0x30, /* MSFT 5.0 */
0x37, 0x0c, 0x01, 0x0f, 0x03, 0x06, 0x2c, 0x2e, /* 7.....,. */
0x2f, 0x1f, 0x21, 0x79, 0xf9, 0x2b, 0xff, 0x00, /* /.!y.+.. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00              /* ...... */
};

/* Frame (342 bytes)  DHCP DISCOVER Endless loop. */
static const unsigned char pkt3[342] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, /* .......P */
0xb6, 0x07, 0xa1, 0x69, 0x08, 0x00, 0x45, 0x00, /* ...i..E. */
0x01, 0x48, 0x00, 0x01, 0x00, 0x00, 0x80, 0x11, /* .H...... */
0x39, 0xa5, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* 9....... */
0xff, 0xff, 0x00, 0x44, 0x00, 0x43, 0x01, 0x34, /* ...D.C.4 */
0x83, 0x9e, 0x01, 0x01, 0x06, 0x00, 0x00, 0xf6, /* ........ */
0x16, 0xc2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, /* .......P */
0xb6, 0x07, 0xa1, 0x69, 0x00, 0x00, 0x00, 0x00, /* ...i.... */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, /* ......c. */
0x53, 0x63, 0x37, 0x01, 0x37, 0x3d, 0x07, 0x01, /* Sc5..=.. */
0x00, 0x50, 0xb6, 0x07, 0xa1, 0x69, 0x0c, 0x0e, /* .P...i.. */
0x43, 0x57, 0x2d, 0x39, 0x57, 0x44, 0x50, 0x4a, /* CW-9WDPJ */
0x56, 0x31, 0x2d, 0x47, 0x41, 0x31, 0x3c, 0x08, /* V1-GA1<. */
0x4d, 0x53, 0x46, 0x54, 0x20, 0x35, 0x2e, 0x30, /* MSFT 5.0 */
0x37, 0x0c, 0x01, 0x0f, 0x03, 0x06, 0x2c, 0x2e, /* 7.....,. */
0x2f, 0x1f, 0x21, 0x79, 0xf9, 0x2b, 0xff, 0x00, /* /.!y.+.. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00              /* ...... */
};

static const UCHAR *test_packet[] = {pkt1, pkt2, pkt3};
static UINT test_packet_size[] = {sizeof(pkt1), sizeof(pkt2), sizeof(pkt3)};
static UINT test_count = sizeof(test_packet_size) / sizeof(UINT);

/* Define what the initial system looks like.  */

#ifdef CTEST
VOID test_application_define(void *first_unused_memory)
#else
void    netx_dhcp_server_options_test_application_define(void *first_unused_memory)
#endif
{

UINT    status;


    /* Setup the working pointer.  */
    pointer =  (CHAR *) first_unused_memory;

    /* Create the server thread.  */
    tx_thread_create(&server_thread, "thread server", server_thread_entry, 0,  
            pointer, DEMO_STACK_SIZE, 
            3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);
    pointer =  pointer + DEMO_STACK_SIZE;

    /* Initialize the NetX system.  */
    nx_system_initialize();

    /* Create the client packet pool.  */
    status =  nx_packet_pool_create(&client_pool, "NetX Main Packet Pool", 1024, pointer, NX_PACKET_POOL_SIZE);
    pointer = pointer + NX_PACKET_POOL_SIZE;

    /* Check for pool creation error.  */
    if (status)
        error_counter++;

    memset(pointer, 53, NX_PACKET_POOL_SIZE);
    
    /* Create the server packet pool.  */
    status =  nx_packet_pool_create(&server_pool, "NetX Main Packet Pool", 1024, pointer, NX_PACKET_POOL_SIZE);
    pointer = pointer + NX_PACKET_POOL_SIZE;

    /* Check for pool creation error.  */
    if (status)
        error_counter++;

    /* Check for IP create errors.  */
    if (status)
        error_counter++;
    
    /* Create an IP instance for the DHCP Server.  */
    status = nx_ip_create(&server_ip, "DHCP Server", NX_DHCP_SERVER_IP_ADDRESS_0, 0xFFFFFF00UL, &server_pool, _nx_ram_network_driver_1024, pointer, 2048, 1);

    pointer =  pointer + 2048;

    /* Check for IP create errors.  */
    if (status)
        error_counter++;
    
    /* Enable ARP and supply ARP cache memory for DHCP Server IP.  */
    status =  nx_arp_enable(&server_ip, (void *) pointer, 1024);
    pointer = pointer + 1024;

    /* Check for ARP enable errors.  */
    if (status)
        error_counter++;
    
    /* Enable UDP traffic.  */
    status =  nx_udp_enable(&server_ip);

    /* Check for UDP enable errors.  */
    if (status)
        error_counter++;

    /* Enable ICMP.  */
    status =  nx_icmp_enable(&server_ip);

    /* Check for errors.  */
    if (status)
        error_counter++;

    return;
}

/* Define the test threads.  */

void    server_thread_entry(ULONG thread_input)
{

UINT        status;
UINT        iface_index;
UINT        addresses_added;
NX_PACKET   *my_packet;
UINT        i;

    printf("NetX Test:   DHCP Server Options Test..................................");

    /* Create the DHCP Server.  */
    status =  nx_dhcp_server_create(&dhcp_server, &server_ip, pointer, DEMO_STACK_SIZE, 
                                   "DHCP Server", &server_pool);
    
    pointer = pointer + DEMO_STACK_SIZE;
    
    /* Check for errors creating the DHCP Server. */
    if (status)
        error_counter++;

    /* Load the assignable DHCP IP addresses for the first interface.  */
    iface_index = 0;

    status = nx_dhcp_create_server_ip_address_list(&dhcp_server, iface_index, START_IP_ADDRESS_LIST_0, 
                                                   END_IP_ADDRESS_LIST_0, &addresses_added);

    /* Check for errors creating the list. */
    if (status)
    {
        error_counter++;
    }

    /* Verify all the addresses were added to the list. */
    if (addresses_added != 10)
    {
        error_counter++;
    }

    status = nx_dhcp_set_interface_network_parameters(&dhcp_server, iface_index, NX_DHCP_SUBNET_MASK_0, 
                                                      NX_DHCP_DEFAULT_GATEWAY_0, NX_DHCP_DNS_SERVER_0);

    /* Check for errors setting network parameters. */
    if (status)
    {
        error_counter++;
    }

    /* Start DHCP Server task.  */
    status = nx_dhcp_server_start(&dhcp_server);

    /* Check for errors starting up the DHCP server.  */
    if (status)
    {
        error_counter++;
    }

    for (i = 0; i < test_count; i++)
    {
        /* Send the DHCP DISCOVER packet.  */
        status = nx_packet_allocate(&client_pool, &my_packet, NX_UDP_PACKET, NX_WAIT_FOREVER);

        /* Check status */
        if (status)
            error_counter++;

        /* Fill in the packet with data. Skip the MAC header.  */
        memcpy(my_packet->nx_packet_prepend_ptr, &test_packet[i][14], test_packet_size[i] - 14);
        my_packet->nx_packet_length = test_packet_size[i] - 14;
        my_packet->nx_packet_append_ptr = my_packet->nx_packet_prepend_ptr + test_packet_size[i] - 14;

        /* Directly receive the DHCP DISCOVER packet.  */
        _nx_ip_packet_deferred_receive(&server_ip, my_packet);
    
        tx_thread_sleep(NX_IP_PERIODIC_RATE);

        if ((i == 0) && (dhcp_server.client_records[0].nx_dhcp_client_option_count))
        {
            error_counter++;
        }

        if ((i == 1) && (dhcp_server.client_records[1].nx_dhcp_client_state == 53))
        {
            error_counter++;
        }

        nx_dhcp_clear_client_record(&dhcp_server, &(dhcp_server.client_records[0]));
    }

    if (error_counter)
    {
        printf("ERROR!\n");
        test_control_return(1);
    }
    else
    {
        printf("SUCCESS!\n");
        test_control_return(0);
    }

    return;
}

#else
#ifdef CTEST
VOID test_application_define(void *first_unused_memory)
#else
void    netx_dhcp_server_options_test_application_define(void *first_unused_memory)
#endif
{
    printf("NetX Test:   DHCP Server Options Test..................................N/A\n");
    test_control_return(3);
}
#endif
